package k8s

import (
	"context"
	"fmt"

	appsv1 "k8s.io/api/apps/v1"
	corev1 "k8s.io/api/core/v1"
	"k8s.io/apimachinery/pkg/labels"
	"k8s.io/apimachinery/pkg/runtime"
	"k8s.io/client-go/rest"
	ctrl "sigs.k8s.io/controller-runtime"
	"sigs.k8s.io/controller-runtime/pkg/client"
	"sigs.k8s.io/controller-runtime/pkg/log"
)

// Manager manages Kubernetes resources and events
type Manager struct {
	client                client.Client
	scheme                *runtime.Scheme
	config                *rest.Config
	eventGenerator        *EventGenerator
	eventProcessor        *EventProcessor
	statefulSetReconciler *StatefulSetReconciler
	pvcReconciler         *PVCReconciler
	pvReconciler          *PVReconciler
	labelSelector         labels.Selector
	namespace             string
}

// ManagerConfig holds configuration for the Kubernetes manager
type ManagerConfig struct {
	ClientConfig    *ClientConfig
	LabelSelector   string
	Namespace       string
	EventBufferSize int
}

// NewManager creates a new Kubernetes manager
func NewManager(config *ManagerConfig) (*Manager, error) {
	// Create Kubernetes client
	k8sClient, err := NewClient(config.ClientConfig)
	if err != nil {
		return nil, fmt.Errorf("failed to create Kubernetes client: %w", err)
	}

	// Parse label selector
	labelSelector, err := labels.Parse(config.LabelSelector)
	if err != nil {
		return nil, fmt.Errorf("failed to parse label selector: %w", err)
	}

	// Create event generator
	eventGenerator := NewEventGenerator(config.EventBufferSize)

	// Create event handler
	eventHandler := NewDefaultEventHandler()

	// Create event processor
	eventProcessor := NewEventProcessor(eventGenerator, eventHandler)

	// Create reconcilers
	statefulSetReconciler := NewStatefulSetReconciler(
		k8sClient.GetClient(),
		k8sClient.GetScheme(),
	)
	pvcReconciler := NewPVCReconciler(
		k8sClient.GetClient(),
		k8sClient.GetScheme(),
	)
	pvReconciler := NewPVReconciler(
		k8sClient.GetClient(),
		k8sClient.GetScheme(),
	)

	return &Manager{
		client:                k8sClient.GetClient(),
		scheme:                k8sClient.GetScheme(),
		config:                k8sClient.GetConfig(),
		eventGenerator:        eventGenerator,
		eventProcessor:        eventProcessor,
		statefulSetReconciler: statefulSetReconciler,
		pvcReconciler:         pvcReconciler,
		pvReconciler:          pvReconciler,
		labelSelector:         labelSelector,
		namespace:             config.Namespace,
	}, nil
}

// Start starts the Kubernetes manager
func (m *Manager) Start(ctx context.Context) error {
	logger := log.FromContext(ctx)
	logger.Info("Starting Kubernetes manager")

	// Start event processor
	m.eventProcessor.Start()

	// Set up controller manager
	mgr, err := ctrl.NewManager(m.config, ctrl.Options{
		Scheme: m.scheme,
		Logger: logger,
	})
	if err != nil {
		return fmt.Errorf("failed to create controller manager: %w", err)
	}

	// Create predicates for filtering
	statefulSetPredicate := CreatePredicateForResource(m.labelSelector, m.namespace)
	pvcPredicate := CreatePredicateForResource(m.labelSelector, m.namespace)
	pvPredicate := CreatePredicateForResource(m.labelSelector, "") // PVs are cluster-scoped

	// Set up StatefulSet controller
	if err := ctrl.NewControllerManagedBy(mgr).
		For(&appsv1.StatefulSet{}).
		WithEventFilter(statefulSetPredicate).
		Complete(m.statefulSetReconciler); err != nil {
		return fmt.Errorf("failed to set up StatefulSet controller: %w", err)
	}

	// Set up PVC controller
	if err := ctrl.NewControllerManagedBy(mgr).
		For(&corev1.PersistentVolumeClaim{}).
		WithEventFilter(pvcPredicate).
		Complete(m.pvcReconciler); err != nil {
		return fmt.Errorf("failed to set up PVC controller: %w", err)
	}

	// Set up PV controller
	if err := ctrl.NewControllerManagedBy(mgr).
		For(&corev1.PersistentVolume{}).
		WithEventFilter(pvPredicate).
		Complete(m.pvReconciler); err != nil {
		return fmt.Errorf("failed to set up PV controller: %w", err)
	}

	// Start the controller manager
	go func() {
		if err := mgr.Start(ctx); err != nil {
			logger.Error(err, "Controller manager failed")
		}
	}()

	logger.Info("Kubernetes manager started successfully")
	return nil
}

// Stop stops the Kubernetes manager
func (m *Manager) Stop() {
	m.eventProcessor.Stop()
	m.eventGenerator.Close()
}

// GetEventChannel returns the event channel for external consumers
func (m *Manager) GetEventChannel() <-chan *ResourceEvent {
	return m.eventGenerator.GetEventChannel()
}

// SendEvent sends an event to the event generator
func (m *Manager) SendEvent(event *ResourceEvent) {
	m.eventGenerator.SendEvent(event)
}

// GetClient returns the underlying Kubernetes client
func (m *Manager) GetClient() client.Client {
	return m.client
}

// GetScheme returns the runtime scheme
func (m *Manager) GetScheme() *runtime.Scheme {
	return m.scheme
}

// ListStatefulSets lists StatefulSets with the configured label selector
func (m *Manager) ListStatefulSets(ctx context.Context) ([]appsv1.StatefulSet, error) {
	var statefulSets appsv1.StatefulSetList
	err := m.client.List(ctx, &statefulSets, &client.ListOptions{
		LabelSelector: m.labelSelector,
		Namespace:     m.namespace,
	})
	if err != nil {
		return nil, fmt.Errorf("failed to list StatefulSets: %w", err)
	}
	return statefulSets.Items, nil
}

// ListPVCs lists PersistentVolumeClaims with the configured label selector
func (m *Manager) ListPVCs(ctx context.Context) ([]corev1.PersistentVolumeClaim, error) {
	var pvcs corev1.PersistentVolumeClaimList
	err := m.client.List(ctx, &pvcs, &client.ListOptions{
		LabelSelector: m.labelSelector,
		Namespace:     m.namespace,
	})
	if err != nil {
		return nil, fmt.Errorf("failed to list PVCs: %w", err)
	}
	return pvcs.Items, nil
}

// ListPVs lists PersistentVolumes with the configured label selector
func (m *Manager) ListPVs(ctx context.Context) ([]corev1.PersistentVolume, error) {
	var pvs corev1.PersistentVolumeList
	err := m.client.List(ctx, &pvs, &client.ListOptions{
		LabelSelector: m.labelSelector,
	})
	if err != nil {
		return nil, fmt.Errorf("failed to list PVs: %w", err)
	}
	return pvs.Items, nil
}
